home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / Tool Chest / Development Platforms / AppsToGo / AppsToGo.src / DTS.Lib / AEWFMT.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-18  |  20.3 KB  |  817 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        AEWFMT.c
  5. ** Written by:    Eric Soldan
  6. **
  7. ** Copyright © 1993 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* You may incorporate this sample code into your applications without
  12. ** restriction, though the sample code has been provided "AS IS" and the
  13. ** responsibility for its operation is 100% yours.  However, what you are
  14. ** not permitted to do is to redistribute the source as "DSC Sample Code"
  15. ** after having made changes. If you're going to re-distribute the source,
  16. ** we require that you make it clear in the source that the code was
  17. ** descended from Apple Sample Code, but that you've made changes. */
  18.  
  19.  
  20.  
  21. /*****************************************************************************/
  22.  
  23.  
  24.  
  25. #include "DTS.Lib2.h"
  26. #include "DTS.Lib.protos.h"
  27.  
  28. #ifndef __ERRORS__
  29. #include <Errors.h>
  30. #endif
  31.  
  32. #ifndef __RESOURCES__
  33. #include "Resources.h"
  34. #endif
  35.  
  36. #ifndef __STRING__
  37. #include <String.h>
  38. #endif
  39.  
  40. #ifndef __TEXTEDITCONTROL__
  41. #include "TextEditControl.h"
  42. #endif
  43.  
  44. #ifndef __TOOLUTILS__
  45. #include "ToolUtils.h"
  46. #endif
  47.  
  48.  
  49.  
  50. /*****************************************************************************/
  51.  
  52.  
  53.  
  54. extern Boolean            gHasAppleEvents, gQuitApplication;
  55. extern TreeObjHndl        gWindowFormats;
  56.  
  57. static pascal OSErr        ReceiveWFMT(AppleEvent *message, AppleEvent *reply, long refcon);
  58. static void                MergeAppResources(void);
  59.  
  60.  
  61.  
  62. /*****************************************************************************/
  63.  
  64.  
  65.  
  66. static AEHandler keywordsToInstall[] = {
  67.     { kCustomEventClass, keyWFMTMessage, ReceiveWFMT }
  68. };
  69.  
  70.  
  71.  
  72. /*****************************************************************************/
  73. /*****************************************************************************/
  74.  
  75.  
  76.  
  77. /* Install our custom AppleEvents.  This is done in addition to installing
  78. ** the required AppleEvents.  InitAppleEvents, which installs the required
  79. ** AppleEvents, must be called first, since it sets up some global values. */
  80.  
  81. #pragma segment AppleEvents
  82. void    InitWFMTAppleEvents(void)
  83. {
  84.     OSErr    err;
  85.     short    i;
  86.  
  87.     if (gHasAppleEvents) {
  88.         for (i = 0; i < (sizeof(keywordsToInstall) / sizeof(AEHandler)); ++i) {
  89.             err = AEInstallEventHandler(
  90.                 keywordsToInstall[i].theEventClass,    /* What class to install.  */
  91.                 keywordsToInstall[i].theEventID,    /* Keywords to install.    */
  92.                 keywordsToInstall[i].theHandler,    /* The AppleEvent handler. */
  93.                 0L,                                    /* Unused refcon.           */
  94.                 false                                /* Only for our app.       */
  95.             );
  96.  
  97.             if (err) {
  98.                 HCenteredAlert(rErrorAlert, nil, (ModalFilterProcPtr)AlertFilter);
  99.                 return;
  100.             }
  101.         }
  102.     }
  103. }
  104.  
  105.  
  106.  
  107. /*****************************************************************************/
  108.  
  109.  
  110.  
  111. /* Send some type of message to the application we are connected to.  Most of the
  112. ** targeting information is the same for various different messages.  Given this,
  113. ** this function builds an AppleEvent, adds the common information to the AppleEvent,
  114. ** and then switches for the various different message types.  A similar factoring
  115. ** process is done at the receiving end. */
  116.  
  117. #pragma segment AppleEvents
  118. OSErr    SendWFMTMessage(FileRecHndl frHndl, TreeObjHndl wobj, short messageType,
  119.                         ResType rtype, short resID, Handle *resHndl)
  120. {
  121.     AEAddressDesc    remoteLoc;
  122.     OSErr            err;
  123.     AppleEvent        theAevt, reply;
  124.     WindowPtr        oldPort;
  125.     Handle            mssgData;
  126.     long            mssgSize, actualSize, oldSize, blockNum;
  127.     DescType        actualType;
  128.     AEKeyword        keym;
  129.     DescType        typem;
  130.  
  131.     if (!(*frHndl)->connect.connected) return(noErr);
  132.  
  133.     oldPort = SetFilePort(frHndl);
  134.  
  135.     theAevt.dataHandle = reply.dataHandle = nil;
  136.         /* Make sure disposing of the descriptors is okay in all cases. */
  137.         /* Even though the AppleEvent manager nils out the handle upon failure,
  138.         ** the below code doesn't necessarily call the AppleEvent manager for each
  139.         ** descriptor.  By etting them to nil here, this allows us to just try to
  140.         ** dispose of the descriptors at the bottom of the function. */
  141.  
  142.     remoteLoc = (*frHndl)->connect.remoteLoc;
  143.  
  144.     err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  145.         kCustomEventClass,            /* Event class.                 */
  146.         typeWFMTMessage,            /* Event ID.                 */
  147.         &remoteLoc,                    /* Address of receiving app. */
  148.         kAutoGenerateReturnID,        /* This value causes the     */
  149.                                     /* AppleEvent manager to     */
  150.                                     /* assign a return ID that     */
  151.                                     /* is unique to the session. */
  152.         kAnyTransactionID,            /* Ignore transaction ID.     */
  153.         &theAevt                    /* Location of event.         */
  154.     );
  155.  
  156.     if (!err)            /* Say what the message is. */
  157.         AEPutParamPtr(&theAevt, keyDirectObject, typeShortInteger, (Ptr)&messageType, sizeof(short));
  158.  
  159.     if (!err) {
  160.         blockNum = 0;
  161.         AEPutParamPtr(&theAevt, typeBlockNum, typeBlockNum, (Ptr)&blockNum, sizeof(long));
  162.     }
  163.  
  164.     /* The stuff that applies to all messages is now done.  Now specifically
  165.     ** handle all the different message types. */
  166.  
  167.     mssgData = nil;
  168.  
  169.     if (!err) {
  170.  
  171.         if (messageType == kMergeAppResourcesMssg)
  172.             messageType =  kSetWFMTMssg;
  173.  
  174.         switch (messageType) {
  175.  
  176.             case kGetWFMTMssg:
  177.                 break;
  178.  
  179.             case kSetWFMTMssg:
  180.                 err = HWriteTree(wobj, mssgData = NewHandle(0));
  181.                 if (!err) {
  182.                     mssgSize = GetHandleSize(mssgData);
  183.                     if (mssgSize > 30000) mssgSize = 30000;
  184.                     HLock(mssgData);
  185.                     err = AEPutParamPtr(
  186.                         &theAevt,
  187.                         keyWFMTMessage,
  188.                         typeWFMTMessage,
  189.                         *mssgData,
  190.                         mssgSize
  191.                     );
  192.                     HUnlock(mssgData);
  193.                 }
  194.                 break;
  195.  
  196.             case kGetAppResourceMssg:
  197.                 err = AEPutParamPtr(
  198.                     &theAevt,
  199.                     typeRSRCType,
  200.                     typeRSRCType,
  201.                     (Ptr)&rtype,
  202.                     sizeof(ResType)
  203.                 );
  204.                 if (!err) {
  205.                     err = AEPutParamPtr(
  206.                         &theAevt,
  207.                         typeRSRCID,
  208.                         typeRSRCID,
  209.                         (Ptr)&resID,
  210.                         sizeof(short)
  211.                     );
  212.                 }
  213.                 break;
  214.         }
  215.     }
  216.  
  217.     if (!err) {
  218.         if ((messageType == kGetWFMTMssg) || (messageType == kGetAppResourceMssg)) {
  219.  
  220.             mssgData = NewHandle(0);
  221.             for (;;) {
  222.  
  223.                 err = AESend(                    /* SEND APPLEEVENT.                */
  224.                     &theAevt,                    /* Our Apple Event to send.        */
  225.                     &reply,                        /* We may have a reply.            */
  226.                     kAEWaitReply,
  227.                     kAENormalPriority,            /* App. send priority.            */
  228.                     300,
  229.                     nil,                        /* No wait, no filter.            */
  230.                     nil                            /* EventFilterProcPtr.            */
  231.                 );
  232.                 if (err) break;
  233.  
  234.                 keym  = (messageType == kGetWFMTMssg) ? keyWFMTMessage  : keyRSRCMessage;
  235.                 typem = (messageType == kGetWFMTMssg) ? typeWFMTMessage : typeRSRCMessage;
  236.                 err = AEGetParamPtr(
  237.                     &reply,                    /* The AppleEvent.              */
  238.                     keym,                    /* AEKeyword                 */
  239.                     typem,                    /* Desired type.             */
  240.                     &actualType,            /* Type code.                 */
  241.                     nil,                    /* Pointer to area for data. */ 
  242.                     0,                        /* Size of data area.         */
  243.                     &mssgSize                /* Returned size of data.     */
  244.                 );
  245.                 if (err) break;
  246.  
  247.                 oldSize = GetHandleSize(mssgData);
  248.                 SetHandleSize(mssgData, oldSize + mssgSize);
  249.                 if (err = MemError()) break;
  250.  
  251.                 HLock(mssgData);
  252.                 err = AEGetParamPtr(
  253.                     &reply,                    /* The AppleEvent.              */
  254.                     keym,                    /* AEKeyword                 */
  255.                     typem,                    /* Desired type.             */
  256.                     &actualType,            /* Type code.                 */
  257.                     *mssgData + oldSize,    /* Pointer to area for data. */ 
  258.                     mssgSize,                /* Size of data area.         */
  259.                     &actualSize                /* Returned size of data.     */
  260.                 );
  261.                 HUnlock(mssgData);
  262.                 if (err) break;
  263.  
  264.                 if (mssgSize < 30000) break;
  265.  
  266.                 ++blockNum;
  267.                 err = AEPutParamPtr(
  268.                     &theAevt,
  269.                     typeBlockNum,
  270.                     typeBlockNum,
  271.                     (Ptr)&blockNum,
  272.                     sizeof(long)
  273.                 );
  274.                 if (err) break;
  275.  
  276.             }
  277.  
  278.             if (messageType == kGetWFMTMssg) {
  279.                 if (!err)
  280.                     HReadTree(wobj, mssgData);
  281.                 if (mssgData)
  282.                     DisposeHandle(mssgData);
  283.             }
  284.             else {
  285.                 if (err)
  286.                     if (mssgData)
  287.                         DisposeHandle(mssgData);
  288.                 *resHndl = mssgData;
  289.             }
  290.         }
  291.     }
  292.  
  293.     if (!err) {        /* If everything looks good... */
  294.         if (messageType == kSetWFMTMssg) {
  295.             do {
  296.                 if (err) {
  297.                     if (mssgData) {
  298.                         DisposeHandle(mssgData);
  299.                         mssgData = nil;
  300.                     }
  301.                     break;
  302.                 }
  303.                 err = AESend(                    /* SEND APPLEEVENT.                */
  304.                     &theAevt,                    /* Our Apple Event to send.        */
  305.                     &reply,                        /* We may have a reply.            */
  306.                     kAEWaitReply,
  307.                     kAENormalPriority,            /* App. send priority.            */
  308.                     300,
  309.                     nil,                        /* No wait, no filter.            */
  310.                     nil                            /* EventFilterProcPtr.            */
  311.                 );
  312.                 if (err) continue;
  313.                 if (mssgData) {
  314.                     mssgSize = GetHandleSize(mssgData);
  315.                     if (mssgSize < 30000) {
  316.                         DisposeHandle(mssgData);
  317.                         mssgData = nil;
  318.                         break;
  319.                     }
  320.                     mssgSize -= 30000;
  321.                     BlockMove(*mssgData + 30000, *mssgData, mssgSize);
  322.                     SetHandleSize(mssgData, mssgSize);
  323.                     if (mssgSize > 30000) mssgSize = 30000;
  324.                     HLock(mssgData);
  325.                     err = AEPutParamPtr(
  326.                         &theAevt,
  327.                         keyWFMTMessage,
  328.                         typeWFMTMessage,
  329.                         *mssgData,
  330.                         mssgSize
  331.                     );
  332.                     HUnlock(mssgData);
  333.                     if (err) continue;
  334.                     ++blockNum;
  335.                     err = AEPutParamPtr(
  336.                         &theAevt,
  337.                         typeBlockNum,
  338.                         typeBlockNum,
  339.                         (Ptr)&blockNum,
  340.                         sizeof(long)
  341.                     );
  342.                 }
  343.             } while (mssgData);
  344.             if (!err) {
  345.                 AEDisposeDesc(&theAevt);
  346.                 AEDisposeDesc(&reply);
  347.                 err = AECreateAppleEvent(        /* CREATE EMPTY APPLEEVENT.     */
  348.                     kCoreEventClass,            /* Event class.                 */
  349.                     kAEOpenApplication,            /* Event ID.                 */
  350.                     &remoteLoc,                    /* Address of receiving app. */
  351.                     kAutoGenerateReturnID,        /* This value causes the     */
  352.                                                 /* AppleEvent manager to     */
  353.                                                 /* assign a return ID that     */
  354.                                                 /* is unique to the session. */
  355.                     kAnyTransactionID,            /* Ignore transaction ID.     */
  356.                     &theAevt                    /* Location of event.         */
  357.                 );
  358.                 if (!err) {
  359.                     err = AESend(                    /* SEND APPLEEVENT.                */
  360.                         &theAevt,                    /* Our Apple Event to send.        */
  361.                         &reply,                        /* We may have a reply.            */
  362.                         kAEWaitReply,
  363.                         kAENormalPriority,            /* App. send priority.            */
  364.                         300,
  365.                         nil,                        /* No wait, no filter.            */
  366.                         nil                            /* EventFilterProcPtr.            */
  367.                     );
  368.                 }
  369.             }
  370.         }
  371.     }
  372.  
  373.     AEDisposeDesc(&theAevt);
  374.     AEDisposeDesc(&reply);
  375.         /* Dispose of the descriptors, created or not.  If not created, no harm done by calling. */
  376.  
  377.     SetPort(oldPort);
  378.     return(err);
  379. }
  380.  
  381.  
  382.  
  383. /*****************************************************************************/
  384.  
  385.  
  386.  
  387. #pragma segment AppleEvents
  388. static pascal OSErr    ReceiveWFMT(AppleEvent *message, AppleEvent *reply, long refcon)
  389. {
  390. #pragma unused (reply, refcon)
  391.  
  392.     OSErr            err;
  393.     short            messageType, oldRes, i, vRefNum, resID;
  394.     char            hstate;
  395.     ResType            rtype;
  396.     Handle            oldr, rsrc;
  397.     WindowPtr        window;
  398.     FileRecHndl        frHndl;
  399.     DescType        actualType;
  400.     long            actualSize, dirID, blockNum, blockBeg, blockSiz;
  401.     MenuHandle        menu;
  402.     long            mssgSize;
  403.     Str32            fileName;
  404.     Handle            mssgData;
  405.     static Handle    accumMssgData;
  406.     static short    count;
  407.  
  408.     err = AEGetParamPtr(        /* GET THE MESSAGE TYPE.     */
  409.         message,                /* The AppleEvent.              */
  410.         keyDirectObject,        /* AEKeyword                 */
  411.         typeShortInteger,        /* Desired type.             */
  412.         &actualType,            /* Type code.                 */
  413.         (Ptr)&messageType,        /* Pointer to area for data. */ 
  414.         sizeof(short),            /* Size of data area.         */
  415.         &actualSize                /* Returned size of data.     */
  416.     );
  417.  
  418.     if (!err) {        /* If everything is cool, then do the specific task... */
  419.  
  420.         switch(messageType) {
  421.  
  422.             case kGetWFMTMssg:
  423.                 mssgData = NewHandle(0);
  424.                 if (gWindowFormats)
  425.                     err = HWriteTree(gWindowFormats, mssgData);
  426.                 if (!err) {
  427.                     err = AEGetParamPtr(
  428.                         message,
  429.                         typeBlockNum,
  430.                         typeBlockNum,
  431.                         &actualType,
  432.                         (Ptr)&blockNum,
  433.                         sizeof(long),
  434.                         &actualSize
  435.                     );
  436.                     if (!err) {
  437.                         mssgSize = GetHandleSize(mssgData);
  438.                         blockBeg = blockNum * 30000;
  439.                         blockSiz = mssgSize - blockBeg;
  440.                         if (blockSiz < 0)     blockSiz = 0;
  441.                         if (blockSiz > 30000) blockSiz = 30000;
  442.                         HLock(mssgData);
  443.                         err = AEPutParamPtr(
  444.                             reply,
  445.                             keyWFMTMessage,
  446.                             typeWFMTMessage,
  447.                             *mssgData + blockBeg,
  448.                             blockSiz
  449.                         );
  450.                     }
  451.                 }
  452.                 DisposeHandle(mssgData);
  453.                 break;
  454.  
  455.             case kSetWFMTMssg:
  456.             case kMergeAppResourcesMssg:
  457.                 err = AEGetParamPtr(
  458.                     message,
  459.                     typeBlockNum,
  460.                     typeBlockNum,
  461.                     &actualType,
  462.                     (Ptr)&blockNum,
  463.                     sizeof(long),
  464.                     &actualSize
  465.                 );
  466.                 if (err) break;
  467.                 err = AEGetParamPtr(
  468.                     message,                /* The AppleEvent.              */
  469.                     keyWFMTMessage,            /* AEKeyword                 */
  470.                     typeWFMTMessage,        /* Desired type.             */
  471.                     &actualType,            /* Type code.                 */
  472.                     nil,                    /* Pointer to area for data. */ 
  473.                     0,                        /* Size of data area.         */
  474.                     &mssgSize                /* Returned size of data.     */
  475.                 );
  476.                 if (err) break;
  477.  
  478.                 if ((blockNum) && (!accumMssgData)) {
  479.                     err = memFullErr;
  480.                     break;
  481.                 }
  482.  
  483.                 if (!blockNum)
  484.                     if (!accumMssgData)
  485.                         accumMssgData = NewHandle(0);
  486.  
  487.                 SetHandleSize(accumMssgData, blockNum * 30000 + mssgSize);
  488.                 err = MemError();
  489.                 if (err) {
  490.                     DisposeHandle(accumMssgData);
  491.                     accumMssgData = nil;
  492.                     break;
  493.                 }
  494.  
  495.                 HLock(accumMssgData);
  496.                 err = AEGetParamPtr(
  497.                     message,                            /* The AppleEvent.              */
  498.                     keyWFMTMessage,                        /* AEKeyword                 */
  499.                     typeWFMTMessage,                    /* Desired type.             */
  500.                     &actualType,                        /* Type code.                 */
  501.                     *accumMssgData + blockNum * 30000,    /* Pointer to area for data. */ 
  502.                     mssgSize,                            /* Size of data area.         */
  503.                     &actualSize                            /* Returned size of data.     */
  504.                 );
  505.                 HUnlock(accumMssgData);
  506.  
  507.                 if (mssgSize == 30000) break;        /* More blocks to come. */
  508.  
  509.                 if (!err) {
  510.                     while (window = GetNextWindow(nil, 0)) {
  511.                         frHndl = (FileRecHndl)GetWRefCon(window);
  512.                         (*frHndl)->fileState.docDirty = false;
  513.                             /* Prevent save-before-closing dialogs. */
  514.                         (*frHndl)->fileState.attributes &= (0xFFFFFFFFL - kwHideOnClose);
  515.                             /* Make sure that we aren't just hiding old windows. */
  516.                         DisposeOneWindow(window, kClose);
  517.                         gQuitApplication = false;
  518.                             /* App may only have one window, and when it is closed,
  519.                             ** the app quits.  This behavior of the app is like DA's.
  520.                             ** Prevent the app from quitting. */
  521.                     }
  522.                     if (!err) {
  523.                         oldRes = CurResFile();
  524.                         UseResFile(gAppResRef);
  525.                         if (oldr = Get1Resource('WFMT', 128)) {
  526.                             RmveResource(oldr);
  527.                             DisposeHandle(oldr);
  528.                         }
  529.                         AddResource(accumMssgData, 'WFMT', 128, nil);
  530.                         ChangedResource(accumMssgData);
  531.                         WriteResource(accumMssgData);
  532.                         UpdateResFile(gAppResRef);
  533.                         DetachResource(accumMssgData);
  534.                         if (!GetFileLocation(gAppResRef, &vRefNum, &dirID, fileName))
  535.                             FlushVol(nil, vRefNum);
  536.                         UseResFile(oldRes);
  537.                     }
  538.                     HReadWindowFormats(accumMssgData);
  539.                     OpenRuntimeOnlyAutoNewWindows();
  540.                 }
  541.  
  542.                 if (accumMssgData) {
  543.                     DisposeHandle(accumMssgData);
  544.                     accumMssgData = nil;
  545.                 }
  546.  
  547.                 if (messageType == kMergeAppResourcesMssg) {
  548.  
  549.                     oldRes = CurResFile();
  550.                     UseResFile(gAppResRef);
  551.                     for (i = Count1Resources('MENU'); i; --i) {
  552.                         menu = (MenuHandle)Get1IndResource('MENU', i);
  553.                         if (!menu) continue;
  554.                         DeleteMenu(**(short **)menu);
  555.                         DisposeMenu(menu);
  556.                     }
  557.                     UseResFile(oldRes);
  558.  
  559.                     MergeAppResources();
  560.  
  561.                     UseResFile(gAppResRef);
  562.                     StandardMenuSetup(rMenuBar, mApple);
  563.                     UseResFile(oldRes);
  564.                 }
  565.  
  566.                 break;
  567.  
  568.             case kGetAppResourceMssg:
  569.                 err = AEGetParamPtr(
  570.                     message,
  571.                     typeRSRCType,
  572.                     typeRSRCType,
  573.                     &actualType,
  574.                     (Ptr)&rtype,
  575.                     sizeof(ResType),
  576.                     &actualSize
  577.                 );
  578.                 if (!err) {
  579.                     err = AEGetParamPtr(
  580.                         message,
  581.                         typeRSRCID,
  582.                         typeRSRCID,
  583.                         &actualType,
  584.                         (Ptr)&resID,
  585.                         sizeof(long),
  586.                         &actualSize
  587.                     );
  588.                 }
  589.                 if (!err) {
  590.                     rsrc = GetAppResource(rtype, resID, nil);
  591.                     if (rsrc) {
  592.                         hstate = HGetState(rsrc);
  593.                         HLock(rsrc);
  594.                         err = AEGetParamPtr(
  595.                             message,
  596.                             typeBlockNum,
  597.                             typeBlockNum,
  598.                             &actualType,
  599.                             (Ptr)&blockNum,
  600.                             sizeof(long),
  601.                             &actualSize
  602.                         );
  603.                         if (!err) {
  604.                             mssgSize = GetHandleSize(rsrc);
  605.                             blockBeg = blockNum * 30000;
  606.                             blockSiz = mssgSize - blockBeg;
  607.                             if (blockSiz < 0)     blockSiz = 0;
  608.                             if (blockSiz > 30000) blockSiz = 30000;
  609.                             err = AEPutParamPtr(
  610.                                 reply,
  611.                                 keyRSRCMessage,
  612.                                 typeRSRCMessage,
  613.                                 *rsrc + blockBeg,
  614.                                 mssgSize
  615.                             );
  616.                         }
  617.                         HSetState(rsrc, hstate);
  618.                     }
  619.                 }
  620.                 break;
  621.  
  622.         }
  623.     }
  624.  
  625.     return(err);
  626. }
  627.  
  628.  
  629.  
  630.  
  631. /*****************************************************************************/
  632. /*****************************************************************************/
  633. /*****************************************************************************/
  634.  
  635.  
  636.  
  637. #pragma segment AppleEvents
  638. static void    MergeAppResources(void)
  639. {
  640.     short                oldRes, numAppTypes, numAppItems, numCpyTypes, numCpyItems;
  641.     short                tt, ii, dd, mergeRsrc, rid, cid, vRefNum;
  642.     char                appAttr, cpyAttr;
  643.     ResType                appType, cpyType, rtype, ddType, ctype;
  644.     long                l, cpySize, dirID;
  645.     ProcessSerialNumber    psn;
  646.     ProcessInfoRec        pinfo;
  647.     FSSpec                fss;
  648.     Str255                rname, cname;
  649.     Str32                dontDo, fileName;
  650.     Handle                appr, cpyr;
  651.     OSErr                err;
  652.  
  653.     oldRes = CurResFile();
  654.  
  655.     pinfo.processInfoLength = sizeof(ProcessInfoRec);
  656.     pinfo.processName       = gAppName;
  657.     pinfo.processAppSpec    = &fss;
  658.  
  659.     psn.lowLongOfPSN  = kCurrentProcess;
  660.     psn.highLongOfPSN = kNoProcess;
  661.     GetProcessInformation(&psn, &pinfo);
  662.  
  663.     pcat(fss.name, "\p copy");
  664.     mergeRsrc = HOpenResFile(fss.vRefNum, fss.parID, fss.name, fsRdPerm);
  665.     if (ResError()) return;
  666.  
  667.     UseResFile(gAppResRef);
  668.     numAppTypes = Count1Types();
  669.  
  670.     for (tt = numAppTypes; tt; --tt) {
  671.         Get1IndType(&appType, tt);
  672.         numAppItems = Count1Resources(appType);
  673.  
  674.         for (ii = numAppTypes; ii; --ii) {
  675.  
  676.             appr = Get1IndResource(appType, ii);
  677.             if (!appr) continue;
  678.  
  679.             GetResInfo(appr, &rid, &rtype, rname);
  680.             appAttr  = GetResAttrs(appr);
  681.  
  682.             if (rtype == 'WFMT') continue;
  683.                 /* ResEdit doesn't modify this one.  DTSFW.App.Editor does. */
  684.  
  685.             if ((rtype == 'STR#') && (rid == 128)) continue;
  686.                 /* This is the resource that describes what resources can be replaced/modified.
  687.                 ** We don't want to replace or modify what is telling us what to do. */
  688.  
  689.             for (dd = 1;; ++dd) {
  690.                 GetIndString(dontDo, 128, dd);
  691.                 if (!dontDo[0]) break;
  692.                 BlockMove(dontDo + 1, &ddType, sizeof(long));
  693.                 if (appType == ddType) break;
  694.             }
  695.             if (dontDo[0]) continue;
  696.  
  697.             UseResFile(mergeRsrc);
  698.             cpyr = Get1Resource(rtype, rid);
  699.             if (cpyr) {
  700.                 GetResInfo(cpyr, &cid, &ctype, cname);
  701.                 cpyAttr = GetResAttrs(cpyr);
  702.                 DetachResource(cpyr);
  703.                 HNoPurge(cpyr);
  704.             }
  705.             UseResFile(gAppResRef);
  706.             appr = Get1IndResource(appType, ii);        /* In case it's purgeable and got purged. */
  707.             if (!appr) {                                /* Just to be really safe. */
  708.                 DisposeHandle(cpyr);
  709.                 continue;
  710.             }
  711.  
  712.             if (!cpyr) {
  713.                 RmveResource(appr);
  714.                 DisposeHandle(appr);
  715.                 continue;
  716.             }
  717.  
  718.             if (appAttr != cpyAttr) {
  719.                 SetResAttrs(appr, cpyAttr);
  720.                 ChangedResource(appr);
  721.                 WriteResource(appr);
  722.             }
  723.             appr = Get1IndResource(appType, ii);        /* In case it's purgeable and got purged. */
  724.             if (!appr) {                                /* Just to be really safe. */
  725.                 DisposeHandle(cpyr);
  726.                 continue;
  727.             }
  728.  
  729.             if (pcmp(rname, cname)) {
  730.                 SetResInfo(appr, rid, cname);
  731.                 ChangedResource(appr);
  732.                 WriteResource(appr);
  733.             }
  734.             appr = Get1IndResource(appType, ii);        /* In case it's purgeable and got purged. */
  735.             if (!appr) {                                /* Just to be really safe. */
  736.                 DisposeHandle(cpyr);
  737.                 continue;
  738.             }
  739.  
  740.             if (GetHandleSize(appr) != (cpySize = GetHandleSize(cpyr))) {
  741.                 HNoPurge(appr);
  742.                 HUnlock(appr);
  743.                 SetHandleSize(appr, cpySize);
  744.                 err = MemError();
  745.                 SetResAttrs(appr, cpyAttr);
  746.                 if (err) {
  747.                     DisposeHandle(cpyr);
  748.                     continue;
  749.                 }
  750.                 BlockMove(*cpyr, *appr, cpySize);
  751.                 ChangedResource(appr);
  752.                 WriteResource(appr);
  753.                 DisposeHandle(cpyr);
  754.                 continue;
  755.             }
  756.  
  757.             for (l = 0; l < cpySize; ++l) {
  758.                 if ((*appr)[l] != (*cpyr)[l]) {
  759.                     BlockMove(*cpyr, *appr, cpySize);
  760.                     ChangedResource(appr);
  761.                     WriteResource(appr);
  762.                     DisposeHandle(cpyr);
  763.                     break;
  764.                 }
  765.             }
  766.             if (l < cpySize) continue;
  767.  
  768.             DisposeHandle(cpyr);
  769.         }
  770.     }
  771.  
  772.     UseResFile(mergeRsrc);
  773.     numCpyTypes = Count1Types();
  774.  
  775.     for (tt = numCpyTypes; tt; --tt) {
  776.         Get1IndType(&cpyType, tt);
  777.         numCpyItems = Count1Resources(cpyType);
  778.  
  779.         for (ii = numCpyItems; ii; --ii) {
  780.  
  781.             cpyr = Get1IndResource(cpyType, ii);
  782.             if (!cpyr) continue;
  783.  
  784.             cpyAttr = GetResAttrs(cpyr);
  785.             GetResInfo(cpyr, &cid, &ctype, cname);
  786.             DetachResource(cpyr);
  787.  
  788.             UseResFile(gAppResRef);
  789.             appr = Get1Resource(ctype, cid);
  790.             UseResFile(mergeRsrc);
  791.  
  792.             if (!appr) {
  793.                 UseResFile(gAppResRef);
  794.                 AddResource(cpyr, ctype, cid, cname);
  795.                 SetResAttrs(cpyr, cpyAttr);
  796.                 ChangedResource(cpyr);
  797.                 WriteResource(cpyr);
  798.                 DetachResource(cpyr);
  799.                 UseResFile(mergeRsrc);
  800.             }
  801.  
  802.             DisposeHandle(cpyr);
  803.         }
  804.     }
  805.  
  806.     UpdateResFile(gAppResRef);
  807.  
  808.     if (!GetFileLocation(gAppResRef, &vRefNum, &dirID, fileName))
  809.         FlushVol(nil, vRefNum);
  810.  
  811.     CloseResFile(mergeRsrc);
  812.     UseResFile(oldRes);
  813. }
  814.  
  815.  
  816.  
  817.